/* -------------------------------------------------------------------------
 *
 * elog.h
 *	  openGauss error reporting/logging definitions.
 *
 *
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 * Portions Copyright (c) 2010-2012 Postgres-XC Development Group
 *
 * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.98 2009/01/01 17:24:02 momjian Exp $
 *
 * -------------------------------------------------------------------------
 */
#ifndef ELOG_H
#define ELOG_H

#include "c.h"
#include "securec.h"
#include "securec_check.h"

/* Error level codes */
#define DEBUG5                                 \
    10 /* Debugging messages, in categories of \
        * decreasing detail. */
#define DEBUG4 11
#define DEBUG3 12
#define DEBUG2 13
#define DEBUG1 14 /* used by GUC debug_* variables */
#define LOG                                         \
    15 /* Server operational messages; sent only to \
        * server log by default. */
#define COMMERROR                                    \
    16 /* Client communication problems; same as LOG \
        * for server reporting, but never sent to    \
        * client. */
#define INFO                                         \
    17 /* Messages specifically requested by user    \
        * (eg VACUUM VERBOSE output); always sent to \
        * client regardless of client_min_messages,  \
        * but by default not sent to server log. */
#define NOTICE                                     \
    18 /* Helpful messages to users about query    \
        * operation; sent to client and server log \
        * by default. */
#define WARNING                                      \
    19 /* Warnings.  NOTICE is for expected messages \
        * like implicit sequence creation by SERIAL. \
        * WARNING is for unexpected messages. */
#define ERROR                                       \
    20 /* user error - abort transaction; return to \
        * known state */
#define ERROR2                                                  \
    21           /* user error - only send error message to the \
                  * client */
#define FATAL 22 /* fatal error - abort process */
#define PANIC 23 /* take down the other backends with me */

/* Which __func__ symbol do we have, if any? */
#ifdef HAVE_FUNCNAME__FUNC
#define PG_FUNCNAME_MACRO __func__
#else
#ifdef HAVE_FUNCNAME__FUNCTION
#define PG_FUNCNAME_MACRO __FUNCTION__
#else
#define PG_FUNCNAME_MACRO NULL
#endif
#endif

#define securec_check(errno, charList, ...)                                                                            \
    {                                                                                                                  \
        if (unlikely(EOK != errno)) {                                                                                  \
            freeSecurityFuncSpace(charList, ##__VA_ARGS__);                                                            \
            switch (errno) {                                                                                           \
                case EINVAL:                                                                                           \
                    elog(ERROR,                                                                                        \
                        "%s : %d : The destination buffer is NULL or not terminated. The second case only occures in " \
                        "function strcat_s/strncat_s.",                                                                \
                        __FILE__,                                                                                      \
                        __LINE__);                                                                                     \
                    break;                                                                                             \
                case EINVAL_AND_RESET:                                                                                 \
                    elog(ERROR, "%s : %d : The source buffer is NULL.", __FILE__, __LINE__);                           \
                    break;                                                                                             \
                case ERANGE:                                                                                           \
                    elog(ERROR,                                                                                        \
                        "%s : %d : The parameter destMax is equal to zero or larger than the macro : "                 \
                        "SECUREC_STRING_MAX_LEN.",                                                                     \
                        __FILE__,                                                                                      \
                        __LINE__);                                                                                     \
                    break;                                                                                             \
                case ERANGE_AND_RESET:                                                                                 \
                    elog(ERROR,                                                                                        \
                        "%s : %d : The parameter destMax is too small or parameter count is larger than macro "        \
                        "parameter SECUREC_STRING_MAX_LEN. The second case only occures in functions "                 \
                        "strncat_s/strncpy_s.",                                                                        \
                        __FILE__,                                                                                      \
                        __LINE__);                                                                                     \
                    break;                                                                                             \
                case EOVERLAP_AND_RESET:                                                                               \
                    elog(ERROR,                                                                                        \
                        "%s : %d : The destination buffer and source buffer are overlapped.",                          \
                        __FILE__,                                                                                      \
                        __LINE__);                                                                                     \
                    break;                                                                                             \
                default:                                                                                               \
                    elog(ERROR, "%s : %d : Unrecognized return type.", __FILE__, __LINE__);                            \
                    break;                                                                                             \
            }                                                                                                          \
        }                                                                                                              \
    }

/* Only used in sprintf_s or scanf_s cluster function */
#define securec_check_ss(errno, charList, ...)                                                                     \
    {                                                                                                              \
        if (errno == -1) {                                                                                         \
            freeSecurityFuncSpace(charList, ##__VA_ARGS__);                                                        \
            elog(ERROR,                                                                                            \
                "%s : %d : The destination buffer or format is a NULL pointer or the invalid parameter handle is " \
                "invoked.",                                                                                        \
                __FILE__,                                                                                          \
                __LINE__);                                                                                         \
        }                                                                                                          \
    }

/*
 * ErrorData holds the data accumulated during any one ereport() cycle.
 * Any non-NULL pointers must point to palloc'd data.
 * (The const pointers are an exception; we assume they point at non-freeable
 * constant strings.)
 */
typedef struct ErrorData {
    int elevel;            /* error level */
    bool output_to_server; /* will report to server log? */
    bool output_to_client; /* will report to client? */
    bool show_funcname;    /* true to force funcname inclusion */
    const char* filename;  /* __FILE__ of ereport() call */
    int lineno;            /* __LINE__ of ereport() call */
    const char* funcname;  /* __func__ of ereport() call */
    const char* domain;    /* message domain */
    char* message;         /* primary error message */
    char* detail;          /* detail error message */
    char* detail_log;      /* detail error message for server log only */
    char* hint;            /* hint message */
    char* context;         /* context message */
    int saved_errno;       /* errno at entry */
} ErrorData;

/* ----------
 * New-style error reporting API: to be used in this way:
 *		ereport(ERROR,
 *				(errcode(ERRCODE_UNDEFINED_CURSOR),
 *				 errmsg("portal \"%s\" not found", stmt->portalname),
 *				 ... other errxxx() fields as needed ...));
 *
 * The error level is required, and so is a primary error message (errmsg
 * or errmsg_internal).  All else is optional.	errcode() defaults to
 * ERRCODE_INTERNAL_ERROR if elevel is ERROR or more, ERRCODE_WARNING
 * if elevel is WARNING, or ERRCODE_SUCCESSFUL_COMPLETION if elevel is
 * NOTICE or below.
 *
 * ereport_domain() allows a message domain to be specified, for modules that
 * wish to use a different message catalog from the backend's.	To avoid having
 * one copy of the default text domain per .o file, we define it as NULL here
 * and have errstart insert the default text domain.  Modules can either use
 * ereport_domain() directly, or preferably they can override the TEXTDOMAIN
 * macro.
 * ----------
 */
#define TEXTDOMAIN "GTM"

#define ereport_domain(elevel, domain, rest) \
    (errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain) ? (errfinish rest) : (void)0)

#define ereport(elevel, rest) ereport_domain(elevel, TEXTDOMAIN, rest)

#define PG_RE_THROW() pg_re_throw()

extern bool errstart(int elevel, const char* filename, int lineno, const char* funcname, const char* domain);
extern void errfinish(int dummy, ...);

extern int errmsg(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));

extern int errmsg_internal(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));

extern int errdetail(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));

extern int errdetail_log(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));

extern int errhint(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));

/* ----------
 * Old-style error reporting API: to be used in this way:
 *		elog(ERROR, "portal \"%s\" not found", stmt->portalname);
 * ----------
 */

#ifdef PC_LINT
#define elog(level, ...)    \
    do {                    \
        if (level >= ERROR) \
            exit(0);        \
    } while (0)
#else
#define elog elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), elog_finish
#endif

extern void elog_start(const char* filename, int lineno, const char* funcname);
extern void elog_finish(int elevel, const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 2, 3)));

/* ----------
 * API for catching ereport(ERROR) exits.  Use these macros like so:
 *
 *		PG_TRY();
 *		{
 *			... code that might throw ereport(ERROR) ...
 *		}
 *		PG_CATCH();
 *		{
 *			... error recovery code ...
 *		}
 *		PG_END_TRY();
 *
 * (The braces are not actually necessary, but are recommended so that
 * pg_indent will indent the construct nicely.)  The error recovery code
 * can optionally do PG_RE_THROW() to propagate the same error outwards.
 *
 * Note: while the system will correctly propagate any new ereport(ERROR)
 * occurring in the recovery section, there is a small limit on the number
 * of levels this will work for.  It's best to keep the error recovery
 * section simple enough that it can't generate any new errors, at least
 * not before popping the error stack.
 *
 * Note: an ereport(FATAL) will not be caught by this construct; control will
 * exit straight through proc_exit().  Therefore, do NOT put any cleanup
 * of non-process-local resources into the error recovery section, at least
 * not without taking thought for what will happen during ereport(FATAL).
 * The PG_ENSURE_ERROR_CLEANUP macros provided by storage/ipc.h may be
 * helpful in such cases.
 * ----------
 */
#define PG_TRY()                                               \
    do {                                                       \
        sigjmp_buf* save_exception_stack = PG_exception_stack; \
        sigjmp_buf local_sigjmp_buf;                           \
        if (sigsetjmp(local_sigjmp_buf, 0) == 0) {             \
        PG_exception_stack = &local_sigjmp_buf

#define PG_CATCH() \
    }              \
    else           \
    {              \
        PG_exception_stack = save_exception_stack;

#define PG_END_TRY()                           \
    }                                          \
    PG_exception_stack = save_exception_stack; \
    }                                          \
    while (0)

int errfunction(const char* funcname);

extern void EmitErrorReport(void* port);

/* GUC-configurable parameters */

typedef enum {
    PGERROR_TERSE,   /* single-line error messages */
    PGERROR_DEFAULT, /* recommended style */
    PGERROR_VERBOSE  /* all the facts, ma'am */
} PGErrorVerbosity;

/* Log destination bitmap */
#define LOG_DESTINATION_STDERR 1
#define LOG_DESTINATION_SYSLOG 2
#define LOG_DESTINATION_EVENTLOG 4
#define LOG_DESTINATION_CSVLOG 8

/* Other exported functions */
extern void pg_re_throw(void);
extern void DebugFileOpen(void);
extern void FlushErrorState(void);

void freeSecurityFuncSpace(char* charList, ...);

/*
 * Write errors to stderr (or by equal means when stderr is
 * not available). Used before ereport/elog can be used
 * safely (memory context, GUC load etc)
 */
extern void write_stderr(const char* fmt, ...)
    /* This extension allows gcc to check the format string for consistency with
       the supplied arguments. */
    __attribute__((format(printf, 1, 2)));
extern void check_gtm_env(const char* input_env_value);
#endif /* GTM_ELOG_H */
